"""Get a list of hosts to avoid for CKI Beaker Jobs."""
import argparse
import datetime
import os

from cki_lib import mariadb
from cki_lib import misc
from cki_lib.logger import get_logger
import sentry_sdk

from cki.cki_tools import _utils

BUCKET_CONFIG_NAME = os.environ.get('BUCKET_CONFIG_NAME')
LIST_PATH = os.environ.get('LIST_PATH', 'broken-machines-list.txt')

THRESHOLD_RECIPES_RUN = misc.get_env_int('THRESHOLD_RECIPES_RUN', 15)
THRESHOLD_BROKEN = os.environ.get('THRESHOLD_BROKEN', 0.7)
MIN_DAYS_TO_CHECK = misc.get_env_int('MIN_DAYS_TO_CHECK', 3)
MAX_DAYS_TO_CHECK = misc.get_env_int('MAX_DAYS_TO_CHECK', 7)
LIMIT_RESULTS = misc.get_env_int('LIMIT_RESULTS', 50)

LOGGER = get_logger('cki.beaker_tools.broken_machines')


def upload(file_content: str):
    """Upload list of broken machines to s3 bucket."""
    bucket = _utils.S3Bucket.from_bucket_string(os.environ[BUCKET_CONFIG_NAME])
    bucket.client.put_object(
        Bucket=bucket.spec.bucket,
        Key=bucket.spec.prefix + LIST_PATH,
        Body=file_content,
        ContentType='text/plain',
    )


def update_list(min_days, max_days, threshold_broken, threshold_recipes_run, limit):
    """Update list of broken machines."""
    db_handler = mariadb.MariaDBHandler()

    query = '''
        SELECT
            recipe_resource.fqdn,
            SUM(CASE WHEN recipe.status = 'Aborted' THEN 1 ELSE 0 END),
            COUNT(fqdn)
        FROM
            recipe
        LEFT JOIN recipe_resource ON
            recipe.id = recipe_resource.recipe_id
        WHERE
            recipe.start_time > %(since)s
        GROUP BY
            recipe_resource.fqdn
        HAVING
            AVG(CASE WHEN recipe.status = 'Aborted' THEN 1 ELSE 0 END) > %(threshold_broken)s AND
            COUNT(fqdn) > %(threshold_recipes_run)s
        LIMIT %(limit)s;
    '''

    hosts = set()

    for days in range(max_days, min_days - 1, -1):
        rows = db_handler.execute(query, {
            'since': datetime.date.today() - datetime.timedelta(days=days),
            'threshold_broken': threshold_broken,
            'threshold_recipes_run': threshold_recipes_run,
            'limit': limit,
        })
        for fqdn, aborted, count in rows:
            if fqdn not in hosts:
                hosts.add(fqdn)
                LOGGER.info('%s aborted %s/%s within %s days', fqdn, aborted, count, days)

    file_content = '\n'.join(sorted(hosts))
    if misc.is_production():
        upload(file_content)


def main():
    """Do everything (parse args, get data from db, create list)."""
    parser = argparse.ArgumentParser(
        description='Get possible broken machines'
    )
    parser.add_argument(
        '--threshold-recipes-run',
        help='Minimum recipes run',
        default=THRESHOLD_RECIPES_RUN,
        type=int,
    )
    parser.add_argument(
        '--threshold-broken',
        help='Threshold for broken machines',
        default=float(THRESHOLD_BROKEN),
        type=float,
    )
    parser.add_argument(
        '--min-days',
        help='Minimum number of days used in the query',
        default=MIN_DAYS_TO_CHECK,
        type=int,
    )
    parser.add_argument(
        '--max-days',
        help='Maximum number of days used in the query',
        default=MAX_DAYS_TO_CHECK,
        type=int,
    )
    parser.add_argument(
        '--limit',
        help='Limit results',
        default=LIMIT_RESULTS,
        type=int,
    )
    args = parser.parse_args()

    update_list(
        args.min_days,
        args.max_days,
        args.threshold_broken,
        args.threshold_recipes_run,
        args.limit
    )


if __name__ == '__main__':
    misc.sentry_init(sentry_sdk)
    main()
